<script lang="ts" setup>
/**
 * Props
 * @defaultFile {String | Array<string>>} 默认文件路径
 *
 * @width {String} 宽度
 *
 * @height {String} 高度
 *
 * @multiple {Boolean} 是否多选
 * 默认 false
 *
 * @limitCount {String} 上传数量
 * 默认 10
 *
 * @limitSize {String} 上传大小
 * 默认 5MB (单位MB)
 *
 * @fileStyle {Object} 已上传图片样式
 *
 * @hiddenRemove {Boolean} 隐藏删除按钮
 * 默认 false
 *
 *
 * @disabled {Boolean} 是否禁用
 * 默认 false
 *
 * Emits
 * @file 返回当前已上传文件地址
 *
 * @uploading 是否正在上传图片中
 *
 * Slot 自定义上传按钮
 */
import { computed, PropType, ref, watch } from 'vue'
import Icon from '@C/Icon.vue'
import { Msg } from '@C/Msg'
import { autoBG, hasUnit, postFileReq } from '@U/common'
import getDate from '@U/getDate'
import { getWeiXinPrivacyAuthorization } from '@U/Auth'
import Image from '@C/Image.vue'
import { hasVarArray, IObjArray } from '@/interface'
import type { IObj } from '@/interface'

const props = defineProps({
  defaultFile: {
    type: String as PropType<string | Array<string>>,
    required: false,
    default: '' || [],
  },
  height: {
    type: String,
    required: false,
    default: '',
  },
  width: {
    type: String,
    required: false,
    default: '',
  },
  disabled: {
    type: Boolean,
    required: false,
    default: false,
  },
  multiple: {
    type: Boolean,
    required: false,
    default: false,
  },
  hiddenRemove: {
    type: Boolean,
    required: false,
    default: false,
  },
  limitCount: {
    type: String,
    required: false,
    default: '10',
  },
  limitSize: {
    type: String,
    required: false,
    default: '5',
  },
  fileStyle: {
    type: Object,
    required: false,
    default: () => ({}),
  },
  uploaderPath: {
    type: String,
    required: false,
    default: '/api/file/upload',
  },
})
const emits = defineEmits(['file', 'uploading'])

// 上传按钮是否显示
const canUpload = computed(() => (props.multiple ? +props.limitCount > file.value.length : !(file.value as IObj)?.path))

// 正在上传
const fileUploadCount = ref(0)
// 上传图片
const uploadPictureFn = () => {
  if (props.disabled) return
  // 获取微信授权
  getWeiXinPrivacyAuthorization(() => {
    uni.chooseImage({
      count: props.multiple ? (+props.limitCount - file.value.length) : 1,
      success(res) {
        const { tempFilePaths } = res;
        (tempFilePaths as Array<string>).forEach((path) => {
          uni.getFileInfo({
            filePath: path,
            success: async (info) => {
              if (info.size >= +props.limitSize * 1024 * 1024) Msg({ msg: `图片最大${props.limitSize}MB` })
              else {
                fileUploadCount.value += 1
                const fileItem = {
                  path,
                  _path: '',
                  created: getDate({ select: ['time'] }).time,
                  state: 1, // 1正在上传 2上传成功 3上传失败
                }
                emits('uploading', true)
                if (props.multiple) {
                  file.value.push(fileItem)
                } else {
                  file.value = fileItem
                }
                await postFileReq(props.uploaderPath, path)
                    .then(res => {
                      fileUploadCount.value -= 1
                      const { statusCode, data } = res
                      const nowData = JSON.parse(data)
                      const newFile: IObj = {
                        path: `${import.meta.env.VITE_SHOUDAO_IMG_URL }/${ nowData.data[0]}`,
                        _path: nowData.data[0],
                        fileType: 'picture',
                      }
                      if (statusCode === 200 && nowData.code === 200) {
                        newFile.state = 2
                      } else {
                        newFile.state = 3
                      }
                      if (props.multiple) {
                        (file.value as IObjArray)[file.value.map((i: IObj) => i.created).indexOf(fileItem.created)] = newFile
                      } else {
                        file.value = newFile
                      }
                    })
                    .catch(err => {
                      fileUploadCount.value -= 1
                      console.log(err)
                      const newFile = {
                        state: 3,
                        path,
                      }
                      if (props.multiple) {
                        (file.value as IObjArray)[file.value.map((i: IObj) => i.created).indexOf(fileItem.created)] = newFile
                      } else {
                        file.value = newFile
                      }
                    })
              }
            },
          })
        })
      },
      fail(err) {
        console.log(err)
      },
    })
  })
}
// 上传视频
const uploadVideoFn = () => {
  if (props.disabled) return
  // 获取微信授权
  getWeiXinPrivacyAuthorization(() => {
    uni.chooseVideo({
      success(res) {
        const { tempFilePath } = res
        uni.getFileInfo({
          filePath: tempFilePath,
          success: async (info) => {
            if (info.size >= +props.limitSize * 1024 * 1024) return Msg({ msg: `视频最大${props.limitSize}MB` })
            fileUploadCount.value += 1
            const fileItem = {
              tempFilePath,
              _path: '',
              created: getDate({ select: ['time'] }).time,
              state: 1, // 1正在上传 2上传成功 3上传失败
            }
            emits('uploading', true)
            if (props.multiple) {
              file.value.push(fileItem)
            } else {
              file.value = fileItem
            }
            await postFileReq(props.uploaderPath, tempFilePath)
                .then(res => {
                  fileUploadCount.value -= 1
                  const { statusCode, data } = res
                  const nowData = JSON.parse(data)
                  const newFile: IObj = {
                    path: `${import.meta.env.VITE_SHOUDAO_IMG_URL }/${ nowData.data[0]}`,
                    _path: nowData.data[0],
                    fileType: 'video',
                  }
                  if (statusCode === 200 && nowData.code === 200) {
                    newFile.state = 2
                  } else {
                    newFile.state = 3
                  }
                  if (props.multiple) {
                    (file.value as IObjArray)[file.value.map((i: IObj) => i.created).indexOf(fileItem.created)] = newFile
                  } else {
                    file.value = newFile
                  }
                })
                .catch(err => {
                  fileUploadCount.value -= 1
                  console.log(err)
                  const newFile = {
                    state: 3,
                    tempFilePath,
                  }
                  if (props.multiple) {
                    (file.value as IObjArray)[file.value.map((i: IObj) => i.created).indexOf(fileItem.created)] = newFile
                  } else {
                    file.value = newFile
                  }
                })
            },
          })
      },
      fail(err) {
        console.log(err)
      },
    })
  })
}
// 删除
const remove = (index?: number) => {
  if (typeof index === 'number') {
    (file.value as IObj)[index as number] = null
    file.value = file.value.filter((i: IObj | null) => i !== null)
  } else {
    file.value = {}
  }
}

const ImageSuffix = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'svg', 'webp']
const VideoSuffix = ['mp4', 'avi', 'mov', 'wmv', 'rmvb']
// 当前已上传文件
const file = ref(<IObj | Array<IObj | null>>(props.multiple ? [] : {}))
watch(
    () => props.defaultFile !== '' && props.defaultFile?.length > 0,
    () => {
      if (hasVarArray(props.defaultFile)) {
        if (!props.defaultFile[0]) return // 没有值不往下执行
        file.value = (props.defaultFile as Array<string>).map((path: string) => {
          let fileType = ''
          const pathArr = path.split('.')
          if (ImageSuffix.includes(pathArr[pathArr.length - 1])) fileType = 'picture'
          else if (VideoSuffix.includes(pathArr[pathArr.length - 1])) fileType = 'video'
          else console.log(`文件名是${path}匹配不到`)
          return ({
            path: /^http/.test(path) ? path : `${import.meta.env.VITE_SHOUDAO_IMG_URL}/${path}`,
            _path: path,
            created: getDate({ select: ['time'] }).time,
            state: 2, // 1正在上传 2上传成功 3上传失败
            fileType,
          })
        })
      } else {
        if (!props.defaultFile) return // 没有值不往下执行
        file.value = {
          path: /^http/.test(props.defaultFile as string) ? props.defaultFile : `${import.meta.env.VITE_SHOUDAO_IMG_URL}/${props.defaultFile}`,
          _path: props.defaultFile,
          created: getDate({ select: ['time'] }).time,
          state: 2, // 1正在上传 2上传成功 3上传失败
        }
      }
    },
)

watch(
    () => JSON.stringify(file.value),
    () => {
      const f = hasVarArray(file.value) ? file.value.map((i: IObj) => i._path) : (file.value as IObj)._path
      emits('file', f)
      if (fileUploadCount.value === 0) emits('uploading', false)
    },
)

const previewImgFn = () => {
  const urls = file.value?.filter(item => item.fileType === 'picture').map(item1 => item1.path)
  uni.previewImage({
    urls,
  })
}
</script>

<template>
  <div :style="{...(height ? {height: hasUnit(height)} : {}), ...(width ? {width: hasUnit(width)} : {})}" class="meidao-upload">
    <template v-if="hasVarArray(file)">
      <div
        v-for="(d, i) in file"
        :key="d.path"
        class="upload_file"
      >
        <div v-if="d.state !== 2" class="upload-file-state">{{ d.state === 1 ? '正在上传' : d.state === 3 ? '上传失败' : '' }}</div>
        <div v-if="d.state === 2 && !hiddenRemove && !disabled" class="upload_file_1">
          <template v-if="d.fileType === 'video'">
            <video :id="d.path" :src="d.path" class="upload_file_1" />
          </template>
          <template v-if="d.fileType === 'picture'">
            <div :style="{background: d.state === 2 ? autoBG(d.path) : autoBG('https://shoudaostatic.oss-cn-shanghai.aliyuncs.com/MEIDAO-ZHIKE/upload_failed.png')}" class="upload_file_1" @tap="previewImgFn" />
          </template>
          <Icon class="upload-file-delete" name="icon-tupianguanbianniu" size="40" @tap.stop="remove(i)" />
        </div>
      </div>
    </template>
    <div v-if="canUpload" class="flex_start">
      <div @tap="uploadPictureFn">
        <slot name="picture">
          <div
            :style="{
              ...(disabled ? {
                borderColor: '#dcdee0',
                backgroundColor: '#dcdee0',
              } : {}),
              ...(height ? {height: hasUnit(height)} : {}),
              ...(width ? {width: hasUnit(width)} : {}),
            }"
            class="upload-btn"
          >
            <Image name="activitySchedule/upload_img" oss size="180" type="png" />
          </div>
        </slot>
      </div>
      <div style="margin-left: 24rpx" @tap="uploadVideoFn">
        <slot name="video">
          <div
            :style="{
              ...(disabled ? {
                borderColor: '#dcdee0',
                backgroundColor: '#dcdee0',
              } : {}),
              ...(height ? {height: hasUnit(height)} : {}),
              ...(width ? {width: hasUnit(width)} : {}),
            }"
            class="upload-btn"
          >
            <Image name="activitySchedule/upload_video" oss size="180" type="png" />
          </div>
        </slot>
      </div>
    </div>
  </div>
</template>

<style lang="less" scoped>
.meidao-upload {
  display: flex;
  flex-flow: wrap;
  position: relative;
  .upload_file {
    width: 180rpx;
    height: 180rpx;
    position: relative;
    border-radius: 20rpx;
    overflow: hidden;
    border: 2rpx solid rgba(0, 0, 0, 0.15);
    margin: 0 24rpx 24rpx 0;
    .upload-file-delete {
      position: absolute;
      top: -2rpx;
      right: -2rpx;
    }
    .upload-file-state {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      right: 0;
      background: rgba(0, 0, 0, 0.45);
      font-size: 30rpx;
      color: white;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .upload_file_1 {
      width: 180rpx;
      height: 180rpx;
    }
  }
  .upload-btn {
    width: 180rpx;
    height: 180rpx;
    margin-bottom: 12px;
    background: white;
    border-radius: 20rpx;
    transition: all .3s;
    overflow: hidden;
    display: flex;
    justify-content: center;
    align-items: center;
    &:active {
      border-color: #ff8002;
    }
  }
}
</style>
